using System;
using System.Collections.Concurrent;
using System.Linq;

namespace Extensions.RateLimiter.SlidingWindow
{
    /// <summary>
    /// 滑动窗口限流策略
    /// </summary>
    public class SlidingWindowThrottleStrategy
    {
        /// <summary>
        /// 限制数量
        /// </summary>
        private readonly long _limitCount;

        /// <summary>
        /// 间隔秒数
        /// </summary>
        private readonly int _intervalSeconds;

        /// <summary>
        /// 缓存
        /// </summary>
        private readonly ConcurrentDictionary<long, long> _cacheMap;

        /// <summary>
        /// 精度值
        /// </summary>
        private const int AccuracyValue = 1000;


        public SlidingWindowThrottleStrategy(long limitCount, int intervalSeconds)
        {
            _limitCount = limitCount;
            _intervalSeconds = intervalSeconds;
            
            //OPTIMIZE:这里可以计算出字典的大小
            _cacheMap = new ConcurrentDictionary<long, long>();
        }

        public bool IsLimit(int n = 1)
        {
            var nowTime = DateTime.Now;

            // 1s = 1 * 1000ms = 1 * 1000 * 1000ns
            var nowMillisecondTicks = DateTime.Now.Ticks / AccuracyValue;

            this._cacheMap.AddOrUpdate(nowMillisecondTicks, 1, (key, value) => value + n);

            var beginMillisecondTicks = nowTime.AddSeconds(-this._intervalSeconds).Ticks / AccuracyValue;

            foreach (var key in this._cacheMap.Keys.Where(key => key < beginMillisecondTicks))
            {
                this._cacheMap.TryRemove(key, out _);
            }

            return this._limitCount >= this._cacheMap.Values.Sum();
        }
    }
}